package com.sg.service.biz.component.nb;

import cn.hutool.core.bean.BeanUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.sg.common.util.CommonFunctionHelper;
import com.sg.common.util.RedisUtil;
import com.sg.dto.biz.component.req.*;
import com.sg.dto.biz.component.res.*;
import com.wicket.okrcomponent.common.exception.BizException;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.http.Method;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsClient;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ： 手工接入方法
 * @version 1.0
 * @since 2022/5/28 15:32
 */
@Service
public class NbOss {

    @Autowired
    private RedisUtil redisUtil;

    @Trace(operationName = "从MINIO生成上传地址")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryObjectStorageTemporaryCredentialsDetailRespDto genMinioUrl() {

        QueryObjectStorageTemporaryCredentialsDetailRespDto retData = new QueryObjectStorageTemporaryCredentialsDetailRespDto();
        try {

            MinioClient minioClient = MinioClient.builder().endpoint("http://192.168.31.221:9090/")
                    .credentials("isFnfrDOAdUjExDUOCif", "yMk7pTUUeMrfKlF96em05zSxlfrkJLItaMG3nKgT").build();
            Map<String, String> reqParams = new HashMap<String, String>();
            reqParams.put("response-content-type", "application/json");
            String product = minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT) //这里必须是PUT，如果是GET的话就是文件访问地址了。如果是POST上传会报错.
                            .bucket("upload")
                            .object(CommonFunctionHelper.getUid() + ".jpg")
                            .expiry(60 * 60 * 24)
                            .extraQueryParams(reqParams)
                            .build());
            System.out.println(product); // 前端直传需要的url地址

            retData.setMinioTemporaryUploadUrl(product);
        } catch (Exception e) {
            System.out.println("Error occurred: " + e);
        }


        return retData;
    }


    @Trace(operationName = "从MINIO获取临时身份")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryObjectStorageTemporaryCredentialsDetailRespDto getMinioSTS() {

        QueryObjectStorageTemporaryCredentialsDetailRespDto retData = new QueryObjectStorageTemporaryCredentialsDetailRespDto();
        String endpointUrl = "http://192.168.31.221:9090";
        String accessKey = "assumerole";
        String secretKey = "nsc_assumerole";
//        String accessKey = "isFnfrDOAdUjExDUOCif";
//        String secretKey = "yMk7pTUUeMrfKlF96em05zSxlfrkJLItaMG3nKgT";

// 创建 STS 客户端
        AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKey, secretKey);
        StsClient stsClient = StsClient.builder()
                .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                .region(Region.of("us-east-1")) // 必需指定一个虚拟地区
                .endpointOverride(URI.create(endpointUrl))
                .build();

// 请求 STS 凭证
        software.amazon.awssdk.services.sts.model.AssumeRoleRequest request = software.amazon.awssdk.services.sts.model.AssumeRoleRequest.builder()
                .roleArn("arn:aws:iam::123456789012:role/demo")
                .roleSessionName("example-session")
                .policy("" +
                        "{\n" +
                        "    \"Version\": \"2012-10-17\",\n" +
                        "    \"Statement\": [\n" +
                        "        {\n" +
                        "            \"Effect\": \"Allow\",\n" +
                        "            \"Action\": [\"s3:*\"],\n" +
                        "            \"Resource\": [\"arn:aws:s3:::*\"]\n" +
                        "        }\n" +
                        "    ]\n" +
                        "}")
                .durationSeconds(3600)
                .build();

        software.amazon.awssdk.services.sts.model.AssumeRoleResponse response = stsClient.assumeRole(request);
        software.amazon.awssdk.services.sts.model.Credentials tempCredentials = response.credentials();

// 输出临时凭证
        System.out.println("Access Key: " + tempCredentials.accessKeyId());
        System.out.println("Secret Key: " + tempCredentials.secretAccessKey());
        System.out.println("Session Token: " + tempCredentials.sessionToken());
        System.out.println("Expiration: " + tempCredentials.expiration());

        retData.setMinioTemporaryIdentityKey(tempCredentials.accessKeyId());

        retData.setMinioTemporaryIdentitySecret(tempCredentials.secretAccessKey());

        retData.setMinioTemporaryIdentityToken(tempCredentials.sessionToken());


        return retData;
    }

    @Trace(operationName = "从阿里云获取临时身份")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryObjectStorageTemporaryCredentialsDetailRespDto getAliSTS() {

        QueryObjectStorageTemporaryCredentialsDetailRespDto retData = new QueryObjectStorageTemporaryCredentialsDetailRespDto();
        // STS服务接入点，例如sts.cn-hangzhou.aliyuncs.com。您可以通过公网或者VPC接入STS服务。
        String endpoint = "sts.cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取步骤1生成的RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = "LTAI5tQBPJqiv8U2GRLwekX5";
        String accessKeySecret = "D1hXosHy8N2DlPGlAhu2YjVMe74FnM";
        // 从环境变量中获取步骤3生成的RAM角色的RamRoleArn。
        String roleArn = "acs:ram::1254596734385686:role/ramosstest";
        // 自定义角色会话名称，用来区分不同的令牌，例如可填写为SessionTest。
        String roleSessionName = "mytest";
        // 临时访问凭证将获得角色拥有的所有权限。
        String policy = null;
        // 临时访问凭证的有效时间，单位为秒。最小值为900，最大值以当前角色设定的最大会话时间为准。当前角色最大会话时间取值范围为3600秒~43200秒，默认值为3600秒。
        // 在上传大文件或者其他较耗时的使用场景中，建议合理设置临时访问凭证的有效时间，确保在完成目标任务前无需反复调用STS服务以获取临时访问凭证。
        Long durationSeconds = 1800L;
        try {
            // 发起STS请求所在的地域。建议保留默认值，默认值为空字符串（""）。
            String regionId = "";
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 添加endpoint。适用于Java SDK 3.12.0以下版本。
            // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            // request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(durationSeconds);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            System.out.println("Expiration: " + response.getCredentials().getExpiration());
            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
            System.out.println("RequestId: " + response.getRequestId());

            retData.setAliyunTemporaryIdentityKey(response.getCredentials().getAccessKeyId());
            retData.setAliyunTemporaryIdentitySec(response.getCredentials().getAccessKeySecret());
            retData.setAliyunTemporaryIdentityToken(response.getCredentials().getSecurityToken());

            // 创建OSSClient实例。
            //设置过期时间为半小时1800L
            long expireTime = 60 * 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB，即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            String dir = "";
            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            OSSClient ossClient = new OSSClient(endpoint, response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret());
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String signature = ossClient.calculatePostSignature(postPolicy);
            retData.setAliyunUploadAuthorizationPolicy(encodedPolicy);
            retData.setAliyunUploadSignature(signature);


        } catch (ClientException e) {
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
            throw new BizException("-1", "调用阿里云失败：" + e, false);
        }


        return retData;
    }


    /**
     * code:getObjectStorageEvidence
     * name:M2查询对象存储临时令牌详情（特殊方法）
     * desc:undefined
     * gen by moon at 11/22/2024, 10:56:49 AM
     **/
    @Trace(operationName = "M2查询对象存储临时令牌详情（特殊方法）")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryObjectStorageTemporaryCredentialsDetailRespDto queryObjectStorageTemporaryCredentialsDetail(QueryObjectStorageTemporaryCredentialsDetailReqDto reqDto) {
//         String key = "调试:" + "funcdebug";
//         String code = (String)redisUtil.get(key);
//         QueryObjectStorageTemporaryCredentialsDetailRespDto retData = new QueryObjectStorageTemporaryCredentialsDetailRespDto();
//         if(code!=null && code.equals("AliSts")){
//             retData  = getAliSTS();
//         }else if(code!=null && code.equals("MinioSts")){
//             retData = getMinioSTS();
//         }else if(code!=null && code.equals("MinioUrl")){
//             retData = genMinioUrl();
//         }
//         QueryObjectStorageTemporaryCredentialsDetailRespDto retData = getAliSTS();
//         QueryObjectStorageTemporaryCredentialsDetailRespDto retData = getMinioSTS();
//         QueryObjectStorageTemporaryCredentialsDetailRespDto retData = genMinioUrl();
        QueryObjectStorageTemporaryCredentialsDetailRespDto retData = new QueryObjectStorageTemporaryCredentialsDetailRespDto();
        // STS服务接入点，例如sts.cn-hangzhou.aliyuncs.com。您可以通过公网或者VPC接入STS服务。
        String endpoint = reqDto.getAliyunOssServiceAddress();
        // 从环境变量中获取步骤1生成的RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = reqDto.getAliyunOssKey();
        String accessKeySecret = reqDto.getAliyunOssSecretKey();
        // 从环境变量中获取步骤3生成的RAM角色的RamRoleArn。
        String roleArn = reqDto.getAliyunOssRoleAuthorizationCode();
        // 自定义角色会话名称，用来区分不同的令牌，例如可填写为SessionTest。
        String roleSessionName = reqDto.getOriginalRoleMemberId();
        // 临时访问凭证将获得角色拥有的所有权限。
        String policy = null;
        // 临时访问凭证的有效时间，单位为秒。最小值为900，最大值以当前角色设定的最大会话时间为准。当前角色最大会话时间取值范围为3600秒~43200秒，默认值为3600秒。
        // 在上传大文件或者其他较耗时的使用场景中，建议合理设置临时访问凭证的有效时间，确保在完成目标任务前无需反复调用STS服务以获取临时访问凭证。
        Long durationSeconds = reqDto.getAliyunOssTemporaryIdentityExpiration();
        try {
            // 发起STS请求所在的地域。建议保留默认值，默认值为空字符串（""）。
            String regionId = "";
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 添加endpoint。适用于Java SDK 3.12.0以下版本。
            // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            // request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(durationSeconds);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            System.out.println("Expiration: " + response.getCredentials().getExpiration());
            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
            System.out.println("RequestId: " + response.getRequestId());

            retData.setAliyunTemporaryIdentityKey(response.getCredentials().getAccessKeyId());
            retData.setAliyunTemporaryIdentitySec(response.getCredentials().getAccessKeySecret());
            retData.setAliyunTemporaryIdentityToken(response.getCredentials().getSecurityToken());

            // 创建OSSClient实例。
            //设置过期时间为半小时1800L
            long expireTime = 60 * 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB，即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            String dir = "";
            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            OSSClient ossClient = new OSSClient(endpoint, response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret());
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String signature = ossClient.calculatePostSignature(postPolicy);
            retData.setAliyunUploadAuthorizationPolicy(encodedPolicy);
            retData.setAliyunUploadSignature(signature);


        } catch (ClientException e) {
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
            throw new BizException("-1", "调用阿里云失败：" + e, false);
        }


        return retData;
    }

    public static void main(String[] args) {
        NbOss instance = new NbOss();
        QueryObjectStorageTemporaryCredentialsDetailRespDto retData = instance.queryObjectStorageTemporaryCredentialsDetail(new QueryObjectStorageTemporaryCredentialsDetailReqDto());


    }

    /**
     * code:getObjectStorageEvidence
     * name:M2查询MINIO临时令牌详情（特殊方法）
     * desc:undefined
     * gen by moon at 12/3/2024, 10:54:43 AM
     **/
    @Trace(operationName = "M2查询MINIO临时令牌详情（特殊方法）")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryMinoTemporaryCredentialsDetailRespDto queryMinoTemporaryCredentialsDetail(QueryMinoTemporaryCredentialsDetailReqDto reqDto) {
        // TODO ruizhe skai dong ; 12/3/2024, 10:54:43 AM
        return new QueryMinoTemporaryCredentialsDetailRespDto();
    }

    /**
     * code:receptionService
     * name:M2接收字段出参（特殊方法）
     * desc:undefined
     * gen by moon at 12/4/2024, 7:24:08 AM
     **/
    @Trace(operationName = "M2接收字段出参（特殊方法）")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public AddObjectStorageConfigRespDto addObjectStorageConfig(AddObjectStorageConfigReqDto reqDto) {
        return BeanUtil.toBean(reqDto, AddObjectStorageConfigRespDto.class);
    }

    /**
     * code:queryMinioTemporaryUploadAddress
     * name:M2查询MINIOURL临时令牌详情（特殊方法）
     * desc:undefined
     * gen by moon at 12/6/2024, 10:02:01 PM
     **/
    @Trace(operationName = "M2查询MINIOURL临时令牌详情（特殊方法）")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public QueryMinioUrlTemporaryCredentialsDetailRespDto queryMinioUrlTemporaryCredentialsDetail(QueryMinioUrlTemporaryCredentialsDetailReqDto reqDto) {
        // TODO ruizhe skai dong ; 12/6/2024, 10:02:01 PM
        QueryMinioUrlTemporaryCredentialsDetailRespDto retData = new QueryMinioUrlTemporaryCredentialsDetailRespDto();
        try {

            MinioClient minioClient = MinioClient.builder().endpoint(reqDto.getMinioServiceAddress())
                    .credentials(reqDto.getMinioKey(), reqDto.getMinioSecretKey()).build();
            Map<String, String> reqParams = new HashMap<String, String>();
            reqParams.put("response-content-type", "application/json");
            String product = minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT) //这里必须是PUT，如果是GET的话就是文件访问地址了。如果是POST上传会报错.
                            .bucket(reqDto.getMinioBucketName())
                            .object(reqDto.getMinioUploadFileObjectName().replaceFirst("^/", ""))
                            .expiry(reqDto.getMinioTemporaryIdentityExpiration().intValue())
                            .extraQueryParams(reqParams)
                            .build());
            System.out.println(product); // 前端直传需要的url地址

            retData.setMinioTemporaryUploadUrl(product);
        } catch (Exception e) {
            System.out.println("Error occurred: " + e);
        }
        return retData;
    }

    /**
     * code:receptionService
     * name:M2获取接收字段
     * desc:undefined
     * gen by moon at 6/3/2025, 1:03:47 PM
     **/
    @Trace(operationName = "M2获取接收字段")
    @Tags({@Tag(key = "参数", value = "arg[0]"),
            @Tag(key = "返回值", value = "returnedObj")})
    public ObtainReceiveFieldsRespDto obtainReceiveFields(ObtainReceiveFieldsReqDto reqDto) {
        return BeanUtil.toBean(reqDto, ObtainReceiveFieldsRespDto.class);
    }
    //手工接入方法
}
